#include "ext_uart.h"
#include "../utility.h"

static void prvRxHandler( void *pvUnused, unsigned portBASE_TYPE uxByteCount );
static void prvTxHandler( void *pvUnused, unsigned portBASE_TYPE uxByteCount );

static XUartLite xExtUartLiteInstance;

static QueueHandle_t xExtUartRxedChars;

static TaskHandle_t xUARTSendingTask = NULL;

static QueueHandle_t xEventQueue = NULL;

/*-----------------------------------------------------------*/

xComPortHandle initExtUart(unsigned portBASE_TYPE uxQueueLength , QueueHandle_t eventQueue)
{
BaseType_t xStatus;

    xEventQueue = eventQueue;
	/* Create the queue used to hold Rx characters. */
	xExtUartRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed char ) );

	/* If the queue was created correctly, then setup the serial port
	hardware. */
	if( xExtUartRxedChars != NULL )
	{
		xStatus = XUartLite_Initialize( &xExtUartLiteInstance, EXT_UART_ID);

		if( xStatus == XST_SUCCESS )
		{
			/* Complete initialisation of the UART and its associated
			interrupts. */
			XUartLite_ResetFifos( &xExtUartLiteInstance );

			/* Install the handlers that the standard Xilinx library interrupt
			service routine will call when Rx and Tx events occur
			respectively. */
			XUartLite_SetRecvHandler( &xExtUartLiteInstance, ( XUartLite_Handler ) prvRxHandler, NULL );
			XUartLite_SetSendHandler( &xExtUartLiteInstance, ( XUartLite_Handler ) prvTxHandler, NULL );

			/* Install the standard Xilinx library interrupt handler itself.
			*NOTE* The xPortInstallInterruptHandler() API function must be used
			for	this purpose. */
			xStatus = xPortInstallInterruptHandler( XPAR_INTC_0_UARTLITE_1_VEC_ID, ( XInterruptHandler ) XUartLite_InterruptHandler, &xExtUartLiteInstance );

			/* Enable the interrupt in the peripheral. */
			XUartLite_EnableIntr( xExtUartLiteInstance.RegBaseAddress );

			/* Enable the interrupt in the interrupt controller.
			*NOTE* The vPortEnableInterrupt() API function must be used for this
			purpose. */
			vPortEnableInterrupt( XPAR_INTC_0_UARTLITE_1_VEC_ID );
		}

		configASSERT( xStatus == pdPASS );
	}

	return ( xComPortHandle ) 0;
}
/*-----------------------------------------------------------*/

portBASE_TYPE xExtUartGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime )
{
portBASE_TYPE xReturn;

	/* The port handle is not required as this driver only supports one port. */
	( void ) pxPort;

	/* Get the next character from the receive queue.  Return false if no
	characters are available, or arrive before xBlockTime expires. */
	if( xQueueReceive( xExtUartRxedChars, pcRxedChar, xBlockTime ) )
	{
		xReturn = pdTRUE;
	}
	else
	{
		xReturn = pdFALSE;
	}

	return xReturn;
}

/*-----------------------------------------------------------*/
// block interface
void vExtUartPutString( xComPortHandle pxPort, signed char * pcString, unsigned short usStringLength )
{
const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 150UL );

	( void ) pxPort;

	/* Note this is the currently sending task. */
	xUARTSendingTask = xTaskGetCurrentTaskHandle();

	/* Output uxStringLength bytes starting from pcString. */
	XUartLite_Send( &xExtUartLiteInstance, ( unsigned char * ) pcString, usStringLength );

	/* Wait in the Blocked state (so not using any CPU time) for the Tx to
	complete. */
	ulTaskNotifyTake( pdTRUE, xMaxBlockTime ); //----- block gw

    Event event;
    makeEvent(&event, usStringLength, EVENT_EXT_UART_TX_OK, pcString);
    xQueueSend( xEventQueue, &event, 0UL );

}
/*-----------------------------------------------------------*/

static void prvRxHandler( void *pvUnused, unsigned portBASE_TYPE uxByteCount )
{
signed char cRxedChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	( void ) pvUnused;
	( void ) uxByteCount;

	/* Place any received characters into the receive queue. */
	while( XUartLite_IsReceiveEmpty( xExtUartLiteInstance.RegBaseAddress ) == pdFALSE )
	{
		cRxedChar = XUartLite_ReadReg( xExtUartLiteInstance.RegBaseAddress, XUL_RX_FIFO_OFFSET);
		xQueueSendFromISR( xExtUartRxedChars, &cRxedChar, &xHigherPriorityTaskWoken );
	}

	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/*-----------------------------------------------------------*/

static void prvTxHandler( void *pvUnused, unsigned portBASE_TYPE uxUnused )
{
BaseType_t xHigherPriorityTaskWoken = ( BaseType_t ) NULL;

	( void ) pvUnused;
	( void ) uxUnused;

	/* Notify the sending that that the Tx has completed. */
	if( xUARTSendingTask != NULL )
	{
		vTaskNotifyGiveFromISR( xUARTSendingTask, &xHigherPriorityTaskWoken );
		xUARTSendingTask = NULL;
	}

	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

// block interface
void vExtUartTx( char * pcMessage , u16 usStringLength)
{
    xComPortHandle xPort;
    vExtUartPutString( xPort, ( signed char * ) pcMessage, usStringLength);
}








